#include "MyChart.h"
#include "stdafx.h"
#include "FCDraw.h"
#include "DataCenter.h"
#include "MainFrame.h"
#include "StockService.h"
#include "FCClientService.h"

MyChart::MyChart(){
    m_cycle = -1;
    m_subscription = 1;
    m_requestID = 0;
    m_lastChangeID = 0;
    m_lastPixel = 11;
    m_clearRequestID = 0;
    m_chart = 0;
    setBackColor(FCColor_None);
    setBorderColor(FCColor_None);
    setLayoutStyle(FCLayoutStyle_TopToBottom);
    setSize({400, 400});
    MainFrame::getMainFrame()->m_charts.add(this);
}


void MyChart::onSearchCode(String code)
{
    m_code = code;
    if (m_cycle > 0)
    {
        m_lastPixel = m_chart->m_hScalePixel;
    }
    searchSecurity(code, m_cycle);
}

void MyChart::callListenerMessageEvent(Object sender, FCMessage *message, Object invoke){
    FCMessage *copyMessage = new FCMessage;
    copyMessage->copy(message);
    char *str = new char[copyMessage->m_bodyLength];
    for(int i = 0; i < copyMessage->m_bodyLength; i++){
        str[i] = message->m_body[i];
    }
    copyMessage->m_body = str;
    m_chart->invoke(copyMessage);
}

void MyChart::bindHistoryDatas(String code, int cycle, ArrayList<SecurityData> historyDatas, bool refresh){
    if (code == m_code && m_cycle == cycle)
    {
        if (MyColor::getStyle() == 0)
        {
            chartToBlack(m_chart);
        }
        else
        {
            chartToWhite(m_chart);
        }
        if (cycle == 0)
        {
            m_chart->m_upColor = USERCOLOR168;
            m_chart->m_downColor = USERCOLOR169;
        }
        m_chart->m_datas.clear();
        m_chart->m_shapes.clear();
        m_chart->resetChartVisibleRecord();
        m_chart->m_lastValidIndex = -1;
        m_chart->checkChartLastVisibleIndex();
        m_chart->m_candlePaddingTop = 30;
        m_chart->m_candlePaddingBottom = 30;
        if (m_cycle == 0)
        {
            m_chart->m_cycle = L"trend";
            m_chart->m_hScaleFormat = L"HH:mm";
            m_chart->m_autoFillHScale = true;
            m_chart->m_magnitude = 100;
            m_chart->m_rightSpace = 0;
            m_chart->m_leftVScaleWidth = 60;
        }
        else if (m_cycle < 1440)
        {
            m_chart->m_cycle = L"minute";
            m_chart->m_hScaleFormat = L"HH:mm";
            m_chart->m_autoFillHScale = false;
            m_chart->m_magnitude = 10000;
            m_chart->m_hScalePixel = m_lastPixel;
            m_lastPixel = m_chart->m_hScalePixel;
            m_chart->m_rightSpace = 20;
            m_chart->m_leftVScaleWidth = 0;
        }
        else
        {
            m_chart->m_cycle = L"day";
            m_chart->m_hScaleFormat = L"yyyy-MM-dd";
            m_chart->m_autoFillHScale = false;
            m_chart->m_magnitude = 10000;
            m_chart->m_hScalePixel = m_lastPixel;
            m_lastPixel = m_chart->m_hScalePixel;
            m_chart->m_rightSpace = 20;
            m_chart->m_leftVScaleWidth = 0;
        }
        Security security;
        if (DataCenter::getSecurityService()->getSecurityByCode(m_code, &security))
        {
            String showCode = security.m_code.substr(0, security.m_code.find(L"."));
            String sName = showCode + L" " + security.m_name;
            m_chart->m_text = sName;
        }
        ArrayList<SecurityData> ary = historyDatas;
        m_chart->m_datas = ary;
        if (cycle == 0 && m_chart->m_datas.size() > 0)
        {
            m_chart->m_firstOpen = m_chart->m_datas.get(m_chart->m_datas.size() - 1).m_close;
        }
        addAvgLine();
        m_chart->resetChartVisibleRecord();
        m_chart->checkChartLastVisibleIndex();
        m_chart->calcChartIndicator();
        if (MainFrame::getMainFrame()->m_latestData.m_requestID != -1 && MainFrame::getMainFrame()->m_latestData.m_requestID == MainFrame::getMainFrame()->m_requestID1)
        {
            //            lock (m_securityDatasCache)
            //            {
            m_securityDatasCache.clear();
            m_securityDatasCache = historyDatas;
            //                m_securityDatasCache.AddRange(historyDatas.ToArray());
            m_clientTickDataCache.m_code = m_code;
            m_clientTickDataCache.m_lastAmount = MainFrame::getMainFrame()->m_latestData.m_amount;
            m_clientTickDataCache.m_lastDate = MainFrame::getMainFrame()->m_latestData.m_date;
            m_clientTickDataCache.m_lastVolume = MainFrame::getMainFrame()->m_latestData.m_volume;
            //            }
            newData(&MainFrame::getMainFrame()->m_latestData, MainFrame::getMainFrame()->m_latestData.m_requestID, false);
        }
        if (refresh)
        {
            invalidate();
        }
    }
}

void MyChart::addAvgLine(){
    if (m_cycle == 0)
    {
        Security security;
        if (DataCenter::getSecurityService()->getSecurityByCode(m_code,  &security))
        {
            int validIndex = -1;
            m_chart->m_shapes.clear();
            BaseShape *shape = 0;
            if (security.m_type > 0)
            {
                shape = new BaseShape();
                shape->m_color = FCColor::rgb(255,255,0);
                shape->m_shapeName = L"avg";
                m_chart->m_shapes.add(shape);
            }
            for (int i = 0; i < m_chart->m_datas.size(); i++)
            {
                if (shape)
                {
                    double avgValue = 0;
                    double sumVolume = 0;
                    double sumPrice = 0;
                    for (int j = 0; j <= i; j++)
                    {
                        sumVolume += m_chart->m_datas.get(j).m_volume;
                        sumPrice += m_chart->m_datas.get(j).m_amount;
                    }
                    if (sumVolume > 0)
                    {
                        avgValue = sumPrice / sumVolume;
                    }else{
                        if(m_chart->m_datas.get(i).m_close > 0){
                            avgValue = m_chart->m_datas.get(i).m_close;
                        }
                    }
                    shape->m_datas.add(avgValue);
                }
                if (m_chart->m_datas.get(i).m_volume > 0)
                {
                    validIndex = i;
                }
            }
            m_chart->m_lastValidIndex = validIndex;
            
        }
    }
}

void MyChart::onAdd(){
    FCSplitLayoutDiv::onAdd();
    if (m_chart == 0)
    {
        FCSplitLayoutDiv *topDiv = new FCSplitLayoutDiv();
        topDiv->setSize({400, 30});
        topDiv->setBackColor(FCColor_None);
        topDiv->setBorderColor(FCColor_None);
        addView(topDiv);
        FCDiv *bottomDiv = new FCDiv();
        bottomDiv->setBackColor(FCColor_None);
        bottomDiv->setBorderColor(FCColor_None);
        addView(bottomDiv);
        getSplitter()->setBounds({0, 30, getWidth(), 31});
        setFirstView(topDiv);
        setSecondView(bottomDiv);
        m_chart = new FCChartEx();
        m_chart->m_showCrossLine = false;
        m_chart->m_myChart = this;
        bottomDiv->addView(m_chart);
        m_chart->setBorderColor(FCColor_None);
        m_chart->setDock(FCDockStyle_Fill);
        m_chart->m_cycle = L"day";
        m_chart->m_allowDragChartDiv = true;
        m_chart->setBorderColor(FCColor_None);
        m_chart->m_crossTipColor = USERCOLOR219;
        m_chart->m_leftVScaleWidth = 0;
        m_chart->m_rightVScaleWidth = 60;
        m_chart->m_candlePaddingTop = 30;
        m_chart->m_hScaleHeight = 25;
        m_chart->m_hScaleTextDistance = 8;
        m_chart->m_candlePaddingBottom = 30;
        if (MyColor::getStyle() == 0)
        {
            chartToBlack(m_chart);
        }
        else
        {
            chartToWhite(m_chart);
        }
        m_chart->m_candleDivPercent = 0.7;
        m_chart->m_volDivPercent = 0.3;
        m_chart->m_indDivPercent = 0;
        m_chart->m_candleStyle = L"rect2";
        m_chart->m_barStyle = L"rect2";

        topDiv->setLayoutStyle(FCLayoutStyle_RightToLeft);
        FCLayoutDiv *rLayout = new FCLayoutDiv();
        rLayout->setBorderColor(FCColor_None);
        rLayout->setBackColor(FCColor_None);
        topDiv->addView(rLayout);
        FCLayoutDiv *lLayout= new FCLayoutDiv();
        lLayout->setBorderColor(FCColor_None);
        lLayout->setBackColor(FCColor_None);
        lLayout->setAllowPreviewsEvent(true);
        lLayout->setAllowDragScroll(true);
        lLayout->setShowHScrollBar(true);
        topDiv->addView(lLayout);
        lLayout->getHScrollBar()->setHeight(0);
        topDiv->getSplitter()->setBounds({topDiv->getWidth(), 0, topDiv->getWidth(), topDiv->getHeight()});
        topDiv->getSplitter()->setBorderColor(FCColor_None);
        topDiv->setFirstView(rLayout);
        topDiv->setSecondView(lLayout);

        ArrayList<String> cycles;
        cycles.add(L"1");
        cycles.add(L"5");
        cycles.add(L"10");
        cycles.add(L"15");
        cycles.add(L"20");
        cycles.add(L"30");
        cycles.add(L"60");
        cycles.add(L"90");
        cycles.add(L"120");
        cycles.add(L"日");
        cycles.add(L"周");
        cycles.add(L"月");
        cycles.add(L"季");
        cycles.add(L"半");
        cycles.add(L"年");
        ArrayList<int> cyclesInts;
        cyclesInts.add(1);
        cyclesInts.add(5);
        cyclesInts.add(10);
        cyclesInts.add(15);
        cyclesInts.add(20);
        cyclesInts.add(30);
        cyclesInts.add(60);
        cyclesInts.add(90);
        cyclesInts.add(120);
        cyclesInts.add(1440);
        cyclesInts.add(10080);
        cyclesInts.add(43200);
        cyclesInts.add(129600);
        cyclesInts.add(259200);
        cyclesInts.add(518400);
        for (int i = 0; i < cycles.size(); i++)
        {
            CycleButton *btnCycle = new CycleButton();
            btnCycle->setBorderColor(FCColor_None);
            btnCycle->setSize({27,30});
            btnCycle->setText(cycles.get(i));
            btnCycle->m_cycle = cyclesInts.get(i);
            btnCycle->m_chart = this;
            btnCycle->setName(FCTran::intToStr(cyclesInts.get(i)));
            lLayout->addView(btnCycle);
            btnCycle->addEvent((FCTouchEventCallBack*)this, L"onclick", this);
            m_cycleButtons.add(btnCycle);
        }

        m_chart->addEvent((FCInvokeEventCallBack*)this, L"oninvoke", this);
    }
}

void MyChart::searchSecurity(String code, int cycle){
    m_code = code;
    int oldReqID = m_requestID;
    m_requestID = FCClientService::getRequestID();
    if (oldReqID != -1)
    {
        DataCenter::getHistoryServiceClient()->removeListener(oldReqID);
    }
    DataCenter::getHistoryServiceClient()->addListener(m_requestID, this, this);
    int realCycle = m_cycle;
    if (realCycle > 0)
    {
        if (realCycle < 1440)
        {
            realCycle = 1;
        }
        else
        {
            realCycle = 1440;
        }
    }
    DataCenter::getHistoryServiceClient()->reqData(m_requestID, m_code, realCycle, 0, 0, 0);
    if (cycle == 0)
    {
        m_chart->m_subComboBox->setVisible(false);
    }
    else
    {
        Security security;
        if (DataCenter::getSecurityService()->getSecurityByCode(m_code, &security))
        {
            if (security.m_type > 0)
            {
                m_chart->m_subComboBox->setVisible(true);
            }
            else
            {
                m_chart->m_subComboBox->setVisible(false);
            }
        }
        else
        {
            m_chart->m_subComboBox->setVisible(false);
        }
    }
}

void MyChart::update(){
    if (m_cycleButtons.size() > 0)
    {
        int dWidth = getWidth() - m_chart->m_rightVScaleWidth;
        int cWidth = dWidth / m_cycleButtons.size();
        int addWidth = 0;
        if (cWidth < 27)
        {
            cWidth = 27;
        }
        else if (cWidth > 35)
        {
            cWidth = 35;
        }
        else
        {
            addWidth = dWidth - cWidth * m_cycleButtons.size();
        }
        for (int i = 0; i < m_cycleButtons.size(); i++)
        {
            m_cycleButtons.get(i)->setWidth(cWidth);
        }
        if (addWidth > 0)
        {
            for (int i = m_cycleButtons.size() - 1; i >= 0; i--)
            {
                if (addWidth > 0)
                {
                    m_cycleButtons.get(i)->setWidth(m_cycleButtons.get(i)->getWidth() + 1);
                    addWidth--;
                }
            }
        }
    }
    FCSplitLayoutDiv::update();
}

void MyChart::setAttribute(const String& name, const String& value){
    if (name == L"cycle")
    {
        m_cycle = FCTran::strToInt(value);
    }
    else if (name == L"candledivpercent")
    {
        m_chart->m_candleDivPercent = FCTran::strToDouble(value);
    }
    else if (name == L"voldivpercent")
    {
        m_chart->m_volDivPercent = FCTran::strToDouble(value);
    }
    else
    {
        FCSplitLayoutDiv::setAttribute(name, value);
    }
}

void MyChart::callTouchEvent(String eventName, Object sender, FCTouchInfo touchInfo, Object invoke){
    FCSplitLayoutDiv::callTouchEvent(eventName, sender, touchInfo, invoke);
    FCView *view = (FCView*)sender;
    if (dynamic_cast<CycleButton*>(view))
    {
        if (m_cycle == 0)
        {
            m_chart->m_hScalePixel = 11;
        }
        else
        {
            m_lastPixel = m_chart->m_hScalePixel;
        }
        CycleButton *cycleButton = (CycleButton*)view;
        m_cycle = FCTran::strToInt(cycleButton->getName());
        cycleButton->getParent()->invalidate();
        searchSecurity(m_code, m_cycle);
        m_chart->focus();
    }
}

void MyChart::chartToBlack(FCChart *chart){
    chart->m_scaleColor = FCColor::rgb(75, 75, 75);
    chart->m_crossLineColor = FCColor::rgb(100, 100, 100);
    chart->m_gridColor = FCColor::rgb(50, 50, 50);
    chart->m_upColor = FCColor::rgb(186, 56, 18);
    chart->m_downColor = FCColor::rgb(31, 182, 177);
    if (m_cycle == 0)
    {
        chart->m_downColor = FCColor::rgb(15, 193, 118);
    }
    chart->m_trendColor = FCColor::rgb(255, 255, 255);
    ArrayList<Long> indicatorColors;
    indicatorColors.add(FCColor::rgb(255, 255, 255));
    indicatorColors.add(FCColor::rgb(255, 255, 0));
    indicatorColors.add(FCColor::rgb(255, 0, 255));
    indicatorColors.add(FCColor::rgb(255, 0, 0));
    indicatorColors.add(FCColor::rgb(0, 255, 255));
    indicatorColors.add(FCColor::rgb(0, 255, 0));
    indicatorColors.add(FCColor::rgb(255, 255, 0));
    indicatorColors.add(FCColor::rgb(255, 255, 255));
    chart->m_indicatorColors = indicatorColors;
    chart->m_candleStyle = L"rect2";
}

void MyChart::chartToWhite(FCChart *chart){
    chart->m_scaleColor = FCColor::rgb(150, 150, 150);
    chart->m_crossLineColor = FCColor::rgb(150, 150, 150);
    chart->m_gridColor = FCColor::rgba(150, 150, 150, 125);
    chart->m_upColor = FCColor::rgb(255, 80, 80);
    chart->m_downColor = USERCOLOR169;
    if (m_cycle == 0)
    {
        chart->m_downColor = FCColor::rgb(15, 193, 118);
    }
    chart->m_trendColor = FCColor::rgb(0, 0, 0);
    ArrayList<Long> indicatorColors;
    indicatorColors.add(FCColor::rgb(50, 50, 50));
    indicatorColors.add(FCColor::rgb(50, 50, 50));
    indicatorColors.add(FCColor::rgb(50, 50, 50));
    indicatorColors.add(FCColor::rgb(50, 50, 50));
    indicatorColors.add(FCColor::rgb(50, 50, 50));
    indicatorColors.add(FCColor::rgb(50, 50, 50));
    indicatorColors.add(FCColor::rgb(100, 100, 100));
    indicatorColors.add(FCColor::rgb(50, 50, 50));
    chart->m_indicatorColors = indicatorColors;
    chart->m_candleStyle = L"rect";
}

int MyChart::insertData(FCChart *chart, SecurityData *securityData){
    if (chart->m_datas.size() > 0)
    {
        double date = securityData->m_date;
        double lastDate = chart->m_datas.get(chart->m_datas.size() - 1).m_date;
        if (date == lastDate)
        {
            chart->m_datas.set(chart->m_datas.size() - 1, *securityData);
        }
        else
        {
            chart->m_datas.add(*securityData);
        }
    }
    else
    {
        chart->m_datas.add(*securityData);
    }
    return 1;
}


void MyChart::newData(SecurityLatestData *latestData, int requestID, bool refresh){
    if (m_cycle == 0)
    {
        m_chart->m_firstOpen = latestData->m_lastClose;
    }
    if (m_cycle == 0 && latestData->m_volume == 0)
    {
        m_clearRequestID = requestID;
        for (int i = 0; i < m_chart->m_datas.size(); i++)
        {
            SecurityData sData = m_chart->m_datas.get(i);
            sData.m_open = 0;
            sData.m_close = 0;
            sData.m_high = 0;
            sData.m_low = 0;
            sData.m_volume = 0;
            sData.m_amount = 0;
        }
        m_chart->m_shapes.clear();
        m_chart->calculateChartMaxMin();
        m_chart->checkChartLastVisibleIndex();
        if (refresh)
        {
            m_chart->invalidate();
        }
    }
    else if (m_clearRequestID == requestID)
    {
        searchSecurity(latestData->m_code, 0);
        m_clearRequestID = -1;
    }
    else
    {
        SecurityData newData;
        newData.m_amount = latestData->m_amount;
        newData.m_volume = latestData->m_volume;
        newData.m_high = latestData->m_high;
        newData.m_low = latestData->m_low;
        newData.m_close = latestData->m_close;
        newData.m_open = latestData->m_open;
        newData.m_date = latestData->m_date;
        bool lastRecordIsVisible = false;
        if (m_chart->m_lastVisibleIndex == m_chart->m_datas.size() - 1)
        {
            lastRecordIsVisible = true;
        }
        m_clientTickDataCache.m_code = latestData->m_code;
        int oldDatasSize = m_securityDatasCache.size();
        StockService::mergeLatestData(latestData->m_code, &m_securityDatasCache, newData, &m_clientTickDataCache, m_cycle);
        if (m_securityDatasCache.size() > 0)
        {
            int startIndex = oldDatasSize - 1;
            if (startIndex < 0)
            {
                startIndex = 0;
            }
            if (m_cycle == 0)
            {
                startIndex = 0;
                m_chart->m_datas = m_securityDatasCache;
            }else{
                for (int i = startIndex; i < m_securityDatasCache.size(); i++)
                {
                    SecurityData securityData = m_securityDatasCache.get(i);
                    if (securityData.m_open > 0 && securityData.m_volume > 0 && securityData.m_amount > 0)
                    {
                        insertData(m_chart, &securityData);
                    }
                }
            }
            m_chart->m_shapes.clear();
            addAvgLine();
            m_chart->calculateChartMaxMin();
            m_chart->checkChartLastVisibleIndex();
            if (lastRecordIsVisible && m_chart->m_lastVisibleIndex != m_chart->m_datas.size() - 1)
            {
                m_chart->m_lastRecordIsVisible = true;
                m_chart->m_lastVisibleIndex = m_chart->m_datas.size() - 1;
                int workingAreaWidth = m_chart->getChartWorkAreaWidth();
                int maxVisibleRecord = m_chart->getChartMaxVisibleCount(m_chart->m_hScalePixel, workingAreaWidth);
                m_chart->m_firstVisibleIndex = m_chart->m_lastVisibleIndex - maxVisibleRecord + 1;
                if (m_chart->m_firstVisibleIndex < 0)
                {
                    m_chart->m_firstVisibleIndex = 0;
                }
            }
            if (refresh)
            {
                m_chart->invalidate();
            }
        }
    }
}

void MyChart::callInvokeEvent(String eventName, Object sender, Object args, Object invoke){
    if (args)
    {
        FCMessage *message = (FCMessage*)args;
        if (message != 0)
        {
            if (message->m_functionID == FUNCTIONID_GETDATA)
            {
                if (message->m_requestID == m_requestID)
                {
                    String code = L"";
                    int cycle = 0;
                    int subscription = 0;
                    double startDate = 0, endDate = 0, nowDate = 0, nowVolume = 0, nowAmount = 0;
                    ArrayList<SecurityData> securityDatas = HistoryServiceClient::getDatas( &code,  &cycle,  &startDate,  &endDate,  &subscription,  &nowDate,  &nowVolume,  &nowAmount, message->m_body, message->m_bodyLength);
                    if (m_cycle > 0)
                    {
                        if (m_subscription == 1)
                        {
                            StockService::ConvertXDR(code, 1, &securityDatas);
                        }
                        else if (m_subscription == 2)
                        {
                            StockService::ConvertXDR(code, 2, &securityDatas);
                        }
                        if (m_cycle < 1440)
                        {
                            if (m_cycle > 1)
                            {
                                ArrayList<SecurityData> newDatas;
                                StockService::multiMinuteSecurityDatas(&newDatas, &securityDatas, m_cycle);
                                securityDatas = newDatas;
                            }
                        }
                        else
                        {
                            if (m_cycle == 10080)
                            {
                                ArrayList<SecurityData> newDatas;
                                StockService::getHistoryWeekDatas(&newDatas, &securityDatas);
                                securityDatas = newDatas;
                            }
                            else if (m_cycle == 43200)
                            {
                                ArrayList<SecurityData> newDatas;
                                StockService::getHistoryMonthDatas(&newDatas, &securityDatas);
                                securityDatas = newDatas;
                            }
                            else if (m_cycle == 129600)
                            {
                                ArrayList<SecurityData> newDatas;
                                StockService::getHistorySeasonDatas(&newDatas, &securityDatas);
                                securityDatas = newDatas;
                            }
                            else if (m_cycle == 259200)
                            {
                                ArrayList<SecurityData> newDatas;
                                StockService::getHistoryHalfYearDatas(&newDatas, &securityDatas);
                                securityDatas = newDatas;
                            }
                            else if (m_cycle == 518400)
                            {
                                ArrayList<SecurityData> newDatas;
                                StockService::getHistoryYearDatas(&newDatas, &securityDatas);
                                securityDatas = newDatas;
                            }
                        }
                    }
                    bindHistoryDatas(code, m_cycle, securityDatas, true);
                }
            }
            delete message->m_body;
            delete message;
        }
    }
}

void MyChart::clearDatas()
{
    m_securityDatasCache.clear();
    m_chart->m_datas.clear();
    m_chart->m_shapes.clear();
    m_chart->invalidate();
}

CycleButton::CycleButton(){
    m_cycle = 0;
    m_chart = 0;
}

Long CycleButton::getPaintingTextColor(){
    if (MyColor::getStyle() == 0)
    {
        return FCColor::rgb(200, 200, 200);
    }
    return FCButton::getPaintingTextColor();
}

void CycleButton::onPaintForeground(FCPaint *paint, const FCRect& clipRect){
    FCButton::onPaintForeground(paint, clipRect);
    int width = getWidth(), height = getHeight();
    paint->drawLine(FCColor_Border, 1, 0, width - 1, 5, width - 1, height - 5);
    if (m_chart != 0 && m_chart->m_cycle != 0 && m_chart->m_cycle == m_cycle)
    {
        paint->fillRect(FCColor_Pushed, 1, 1, width - 1, height - 1);
        paint->drawRect(USERCOLOR109, 1, 0, 1, 1, width - 1, height - 1);
    }
}

